local guixin = fk.CreateSkill{
  name = "swis__guixin",
}

Fk:loadTranslationTable{
  ["swis__guixin"] = "归心",
  [":swis__guixin"] = "每名角色限X次（X为本局游戏你对其、其对你造成的伤害数之和），你可以于对应时机发动其他角色武将牌上的技能。",

  ["#swis__guixin-choose"] = "归心：多名角色拥有“%arg”，请选择你本次发动“%arg”的来源角色",
  ["#swis__guixin-tip"] = "可发动%arg次"
}

guixin:addAcquireEffect(function (self, player, is_start)
  local room = player.room
  local mark = {}
  local times = {}
  if not is_start then
    room.logic:getActualDamageEvents(1, function (e)
      if e.data.to and e.data.from and table.contains({e.data.from, e.data.to}, player) then
        for _, p in ipairs({e.data.to, e.data.from}) do
          if p ~= player then
            times[p] = {times[p] or 0} + 1
          end
        end
      end
      return false
    end)
  end
  for _, p in ipairs(room:getOtherPlayers(player, false)) do
    table.insert(mark, { id = p.id, times = times[p] or 0 })
  end
  room:setPlayerMark(player, guixin.name, mark)
end)

---@param player Player
---@param target Player
---@return integer
local getPlayerTimes = function (player, target)
  for _, spec in ipairs(player:getMark(guixin.name)) do
    if spec.id == target.id then
      return spec.times
    end
  end
  return 0
end

---@param player ServerPlayer
---@return string[]
local getGuixinSkills = function (player)
  local room = player.room
  local skills = {}
  for _, spec in ipairs(player:getMark(guixin.name)) do
    local target = room:getPlayerById(spec.id)
    if spec.times > 0 then
      table.insertTable(skills, Fk.generals[target.general].other_skills)
    end
  end
  return skills
end

---@param player ServerPlayer
---@param target ServerPlayer
---@param num integer
local addTime = function (player, target, num)
  local room = player.room
  local mark = player:getMark(guixin.name)
  if getPlayerTimes(player, target) == 0 then
    for _, spec in ipairs(mark) do
      if spec.id == target.id then
        local skills = Fk.generals[target.general].other_skills
        for _, skill in ipairs(skills) do
          if not Fk.skills[skill]:isInstanceOf(StatusSkill) then
            player:addFakeSkill(skill)
            player:prelightSkill(skill, true)
          end
        end
      end
    end
  end
  for _, spec in ipairs(mark) do
    if spec.id == target.id then
      spec.times = spec.times + num
    end
  end
  room:setPlayerMark(player, guixin.name, mark)
end

---@param player ServerPlayer
---@param target ServerPlayer
local reduceTime = function (player, target)
  local room = player.room
  local mark = player:getMark(guixin.name)
  for _, spec in ipairs(mark) do
    if spec.id == target.id then
      spec.times = spec.times - 1
      if spec.times == 0 then
        local skills = Fk.generals[target.general].other_skills
        for _, skill in ipairs(skills) do
          if not Fk.skills[skill]:isInstanceOf(StatusSkill) then
            player:loseFakeSkill(skill)
          end
        end
      end
    end
  end
  room:setPlayerMark(player, guixin.name, mark)
end

Fk:addTargetTip{
  name = "swis__guixin_tip",
  target_tip = function(self, player, to_select, selected, selected_cards, card, selectable)
    if not selectable then return end
    return "#swis__guixin-tip:::"..getPlayerTimes(player, to_select)
  end,
}

guixin:addEffect(fk.Damage, {
  can_refresh = function (self, event, target, player, data)
    return player:hasSkill(guixin.name, true) and player == target and player ~= data.to
  end,
  on_refresh = function (self, event, target, player, data)
    addTime(player, data.to, data.damage)
  end,
})

guixin:addEffect(fk.Damaged, {
  can_refresh = function (self, event, target, player, data)
    return player:hasSkill(guixin.name, true) and player == target and data.from and player ~= data.from
  end,
  on_refresh = function (self, event, target, player, data)
    addTime(player, data.from, data.damage)
  end,
})

guixin:addEffect(fk.EventAcquireSkill, {
  can_refresh = function (self, event, target, player, data)
    return player:hasSkill(guixin.name, true) and player ~= target
    and getPlayerTimes(player, target) > 0 and not data.skill:isInstanceOf(StatusSkill)
  end,
  on_refresh = function (self, event, target, player, data)
    if table.contains(getGuixinSkills(player), data.skill.name) then
      player:addFakeSkill(data.skill.name)
      player:prelightSkill(data.skill.name, true)
    end
  end,
})

guixin:addEffect(fk.EventLoseSkill, {
  can_refresh = function (self, event, target, player, data)
    return player:hasSkill(guixin.name, true) and player ~= target
    and getPlayerTimes(player, target) > 0
  end,
  on_refresh = function (self, event, target, player, data)
    if not table.contains(getGuixinSkills(player), data.skill.name) then
      player:loseFakeSkill(data.skill.name)
    end
  end,
})

guixin:addEffect(fk.SkillEffect, {
  anim_type = "special",
  can_trigger = function (self, event, target, player, data)
    return player == target and player:hasSkill(guixin.name) and table.contains(getGuixinSkills(player), data.skill:getSkeleton().name)
  end,
  on_cost = function (self, event, target, player, data)
    local room = player.room
    local from = table.filter(player:getMark(guixin.name), function (spec)
      return spec.times > 0 and table.contains(Fk.generals[room:getPlayerById(spec.id).general].other_skills, data.skill:getSkeleton().name)
    end)
    from = table.map(from, function (spec) return room:getPlayerById(spec.id) end)
    if #from > 1 then
      from = room:askToChoosePlayers(player, {
        targets = from,
        min_num = 1,
        max_num = 1,
        skill_name = guixin.name,
        cancelable = false,
        prompt = "#swis__guixin-choose:::"..Fk:translate(data.skill:getSkeleton().name),
        target_tip_name = "swis__guixin_tip",
      })
    end
    event:setCostData(self, from[1])
    return true
  end,
  on_use = function (self, event, target, player, data)
    local from = event:getCostData(self) ---@type ServerPlayer
    reduceTime(player, from)
  end
})

guixin:addEffect("invalidity", {
  recheck_invalidity = true,
  invalidity_func = function (self, from, skill)
    local mark = from:getMark(guixin.name)
    if mark == 0 then return end
    return not from:hasSkill(guixin.name) and table.find(mark, function (spec)
      return table.contains(spec.skills, skill:getSkeleton().name)
    end)
  end,
})

return guixin